package com.sfzlot.dev.netty.utils;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;

/**
 * Created by 蔡志杰 on 2017/7/13.
 */
public class ByteUtil {

	/**
     * Convert hex string to byte[]
     * @param hexString the hex string
     * @return byte[]
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }
	
    /**
     * 数组转成十六进制字符串
     * @param b
     * @return HexString
     */
    public static String toHexString(byte[] b){
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < b.length; ++i){
            buffer.append(toHexString(b[i]));
        }
        return buffer.toString();
    }
    
    public static String toHexString(byte b){
        String s = Integer.toHexString(b & 0xFF);
        if (s.length() == 1){
            return "0" + s;
        }else{
            return s;
        }
    }
	
	/**
     * 将两个byte组成一个int
     * 0xFF,0xFE表示异常，返回-1
     * 0xFF,0xFF表示无效，返回-2
     * @param b1
     * @param b2
     * @return
     */
    public static int getIntFromBytes(byte b1,byte b2){
        int result;
        int num1 = (b1&0xFF);
        int num2 = (b2&0xFF);
        if ((num1 == 0xFF)&&(num2 == 0xFE)){
            result = -1;
        }else if ((num1 == 0xFF)&&(num2 == 0xFF)){
            result = -2;
        }else{
           result = (num1 << 8) | num2;
        }
        return  result;
    }

    /**
     * 将byte转回int
     * Java 总是把 byte 当做有符处理；我们可以通过将其和 0xFF 进行二进制与得到它的无符值
     * @param b1
     * @return
     */
    public static int getIntFromByte(byte b1){
        return b1&0xFF;
    }

    /**
     * 0xFE表示异常，返回-1
     * 0xFF表示无效，返回-2
     * @param b1
     * @return
     */
    public static int getIntFormByteWithException(byte b1){
        int num = b1&0xFF;
        if (num == 0xFE){
            return  -1;
        }else if (num == 0xFF){
            return -2;
        }else{
            return num;
        }
    }

    /**
     * 将四个byte组成一个int
     * 0xFF,0xFF,0xFF,0xFE表示异常，返回-1
     * 0xFF,0xFF,0xFF,0xFF表示无效，返回-2
     * @param b1
     * @param b2
     * @param b3
     * @param b4
     * @return
     */
    public static int getIntFromFourBytes(byte b1,byte b2,byte b3,byte b4){
        int num1 = (b1&0xFF);
        int num2 = (b2&0xFF);
        int num3 = (b3&0xFF);
        int num4 = (b4&0xFF);
        int result;
        if ((num1==0xFF)&&(num2==0xFF)&&(num3==0xFF)&&(num4==0xFE)){
            result = -1;
        }else if ((num4==0xFF)&&(num1==0xFF)&&(num2==0xFF)&&(num3==0xFF)){
            result = -2;
        }else{
            result = ((num1 << 24)|(num2 << 16)|(num3 << 8) | num4);
        }
        return  result;
    }
	
    /** 
     * @方法功能 InputStream 转为 byte 
     * @param inStream InputStream
     * @return 字节数组 
     * @throws Exception 
     */  
    public static byte[] inputStream2Byte(InputStream inStream)  
            throws Exception {  
        int count = 0;  
        while (count == 0) {  
            count = inStream.available();  
        }  
        byte[] b = new byte[count];  
        inStream.read(b);  
        return b;  
    }  
  
    /** 
     * @方法功能 byte 转为 InputStream 
     * @param b 字节数组
     * @return InputStream 
     * @throws Exception 
     */  
    public static InputStream byte2InputStream(byte[] b) throws Exception {  
        InputStream is = new ByteArrayInputStream(b);  
        return is;  
    }  
  
	public static byte[] shortToBytes(short n) {
		byte[] b = new byte[2];
		b[1] = (byte) (n & 0xff);
		b[0] = (byte) ((n >> 8) & 0xff);
		return b;
	}

	public static short bytesToShort(byte[] b) {
		return (short) (b[1] & 0xff | (b[0] & 0xff) << 8);
	}
  
	/**
	 * int --> byte[] 占4位字节
	 * 高位在前，低位在后  海纳校园解析此方法
	 * 如：100000 --> 000186a0
	 * @param num
	 * @return 
	 */
    public static byte[] int2bytes(int num){  
        byte[] result = new byte[4];  
        result[0] = (byte)((num >>> 24) & 0xff);//说明一  
        result[1] = (byte)((num >>> 16)& 0xff );  
        result[2] = (byte)((num >>> 8) & 0xff );  
        result[3] = (byte)((num >>> 0) & 0xff );  
        return result;  
    }  
      
    /**
	 * byte[] --> int 占4位字节
	 * 高位在前，低位在后  海纳校园解析此方法
	 * 如：000186a0 --> 100000
	 * @param bytes
	 * @return 
	 */
    public static int bytes2int(byte[] bytes){  
        int result = 0;  
        if(bytes.length == 4){  
            int a = (bytes[0] & 0xff) << 24;//说明二  
            int b = (bytes[1] & 0xff) << 16;  
            int c = (bytes[2] & 0xff) << 8;  
            int d = (bytes[3] & 0xff);  
            result = a | b | c | d;  
        }  
        return result;  
    } 
    
//    /** 
//     * @方法功能 整型与字节数组的转换 高位在后，低位在前  
//     * @param 整型 
//     * @return 四位的字节数组 
//     */  
//    public static byte[] intToByte(int i) {  
//        byte[] bt = new byte[4];  
//        bt[0] = (byte) (0xff & i);  
//        bt[1] = (byte) ((0xff00 & i) >> 8);  
//        bt[2] = (byte) ((0xff0000 & i) >> 16);  
//        bt[3] = (byte) ((0xff000000 & i) >> 24);  
//        return bt;  
//    }  
//  
//    /** 
//     * @方法功能 字节数组和整型的转换 高位在后，低位在前  
//     * @param 字节数组 
//     * @return 整型 
//     */  
//    public static int bytesToInt(byte[] bytes) {  
//        int num = bytes[0] & 0xFF;  
//        num |= ((bytes[1] << 8) & 0xFF00);  
//        num |= ((bytes[2] << 16) & 0xFF0000);  
//        num |= ((bytes[3] << 24) & 0xFF000000);  
//        return num;  
//    }  
  
    /** 
     * @方法功能 字节数组和长整型的转换 
     * @param number 字节数组
     * @return 长整型 
     */  
    public static byte[] longToByte(long number) {  
        long temp = number;  
        byte[] b = new byte[8];  
        for (int i = 0; i < b.length; i++) {  
            b[i] = new Long(temp & 0xff).byteValue();  
            // 将最低位保存在最低位  
            temp = temp >> 8;  
            // 向右移8位  
        }  
        return b;  
    }  
  
    /** 
     * @方法功能 字节数组和长整型的转换 
     * @param b 字节数组
     * @return 长整型 
     */  
    public static long byteToLong(byte[] b) {  
        long s = 0;  
        long s0 = b[0] & 0xff;// 最低位  
        long s1 = b[1] & 0xff;  
        long s2 = b[2] & 0xff;  
        long s3 = b[3] & 0xff;  
        long s4 = b[4] & 0xff;// 最低位  
        long s5 = b[5] & 0xff;  
        long s6 = b[6] & 0xff;  
        long s7 = b[7] & 0xff; // s0不变  
        s1 <<= 8;  
        s2 <<= 16;  
        s3 <<= 24;  
        s4 <<= 8 * 4;  
        s5 <<= 8 * 5;  
        s6 <<= 8 * 6;  
        s7 <<= 8 * 7;  
        s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;  
        return s;  
    } 
    
	/**
	 * 将字符串转为指定长度的数组，不足位数，在前面补0
	 * @param string
	 * @param byteSize
	 * @return
	 */
	public static byte[] stringToByte(String string, int byteSize) {
		// 如果传入的字符串为null，直接返回指定长度的byte数据，全部填充0x00
		if (string == null) {
			return new byte[byteSize];
		}
		try {
			byte[] strBytes = string.getBytes("UTF-8");
			int strLength = strBytes.length;
			if (strLength < byteSize) {
				byte[] bytes = new byte[byteSize];
				// 先补0
				int diff = byteSize - strLength;
				for (int i = 0; i < diff; i++) {
					bytes[i] = 0;
				}
				// 再写字符串
				for (int i = 0; i < strLength; i++) {
					bytes[diff + i] = strBytes[i];
				}
				return bytes;
			} else if (strLength > byteSize) {
				// 截短过长的字符串
				return Arrays.copyOf(strBytes, byteSize);
			} else {
				return strBytes;
			}
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return new byte[byteSize];
	}

	/**
	 * Convert char to byte
	 * @param c char
	 * @return byte
	 */
	private static byte charToByte(char c) {
		return (byte) "0123456789ABCDEF".indexOf(c);
	}
	
	/**
	 * 将多个数组合并在一起<br>
	 * 忽略null的数组
	 * 
	 * @param arrays 数组集合
	 * @return 合并后的数组
	 */
	@SafeVarargs
	public static byte[] addAll(byte[]... arrays) {
		if (arrays.length == 1) {
			return arrays[0];
		}

		int length = 0;
		for (byte[] array : arrays) {
			if (array == null) {
				continue;
			}
			length += array.length;
		}
		byte[] result = new byte[length];

		length = 0;
		for (byte[] array : arrays) {
			if (array == null) {
				continue;
			}
			System.arraycopy(array, 0, result, length, array.length);
			length += array.length;
		}
		return result;
	}
	
	/**
	 * 时间转为十六进制
	 * @param date
	 * @return
	 * 修改日期:2017年8月3日下午2:54:15
	 */
    public static byte[] timeToBytes(Date date) {
    	Calendar calendar = Calendar.getInstance();
    	calendar.setTime(date);
    	Integer YY = calendar.get(Calendar.YEAR) -2000 ;
    	Integer MM = calendar.get(Calendar.MONTH)+1;
    	Integer DD = calendar.get(Calendar.DATE);
    	Integer HH = calendar.get(Calendar.HOUR_OF_DAY);
    	Integer NN = calendar.get(Calendar.MINUTE);
    	Integer SS = calendar.get(Calendar.SECOND);
    	byte[] bytes = new byte[6];
    	bytes[0]= YY.byteValue();
    	bytes[1]= MM.byteValue();
    	bytes[2]= DD.byteValue();
    	bytes[3]= HH.byteValue();
    	bytes[4]= NN.byteValue();
    	bytes[5]= SS.byteValue();
    	return bytes;
    }
    
    /**
     * 算出校验码,缺少校验码的报文
     * @param messageBytes byte[]
     * @return
     */
    public static byte getByteCheckPassByLack(byte[] messageBytes) {
    	//校验码
        byte destCheckCharacter = messageBytes[2];
        for (int i = 3; i <messageBytes.length; i++) {
            destCheckCharacter ^= messageBytes[i];
        }
        return destCheckCharacter;
	}
    
    /**
     * 算出校验码,完整的报文
     * @param messageBytes byte[]
     * @return
     */
    public static byte getByteCheckPass(byte[] messageBytes) {
    	//校验码
        byte destCheckCharacter = messageBytes[2];
        for (int i = 3; i <messageBytes.length-1; i++) {
            destCheckCharacter ^= messageBytes[i];
        }
        return destCheckCharacter;
	}
    
    /**
     * 获取校验码
     * @param messageBytes
     * @return
     */
    public static boolean getCheckPass(byte[] messageBytes) {
		boolean flag = false;
		byte destCheckCharacter =getByteCheckPass(messageBytes);
		//查看是否检验通过
        int checkCharacter = messageBytes[messageBytes.length-1];
        if (checkCharacter == destCheckCharacter){
            //如果检验通过读取消息
        	flag = true;
        }else{
            //如果校验不通过，不读取消息，返回校验不通过
        	flag = false;
        }
        return flag;
	}
   
    /**
     * 获取校验码
     * @param sb
     * @return
     */
	public static boolean checkCharcter(String sb) {
		byte[] preBytes = hexStringToBytes(sb);
		return getCheckPass(preBytes);
	}
    
}
